package cn.edu.zjut.medlinebackend.service.impl;
import java.util.*;

import cn.edu.zjut.medlinebackend.esdao.PostEsDao;
import cn.edu.zjut.medlinebackend.mapper.PostMapper;
import cn.edu.zjut.medlinebackend.model.Post;
import cn.edu.zjut.medlinebackend.model.dto.PictureEsDTO;
import cn.edu.zjut.medlinebackend.model.dto.PostEsDTO;
import cn.edu.zjut.medlinebackend.model.dto.PostQuery;
import cn.edu.zjut.medlinebackend.model.vo.PostByTagVO;
import cn.edu.zjut.medlinebackend.model.vo.PostVO;
import cn.edu.zjut.medlinebackend.service.PictureService;
import cn.edu.zjut.medlinebackend.service.PostService;
import cn.edu.zjut.medlinebackend.utils.MyUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.stream.Collectors;

/**
 * @author 86182
 * @description 针对表【post(帖子)】的数据库操作Service实现
 * @createDate 2023-11-21 19:47:27
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post>
        implements PostService {

    @Resource
    private PostMapper postMapper;

    @Resource
    private PostEsDao postEsDao;
    @Resource
    private FavoriteServiceImpl favoriteService;
    @Resource
    private UserServiceImpl userService;
    @Resource
    private PictureService pictureService;

    @Resource
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public List<Post> getBySearchText(PostQuery postQuery) {
        String searchText = postQuery.getSearchText();
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        // 拼接查询条件
        if (StringUtils.isNotBlank(searchText)) {
            queryWrapper.like("title", searchText).or().like("content", searchText);
        }

        return postMapper.selectList(queryWrapper);
    }

    @Override
    public Page<PostEsDTO> getPostFromEs(PostQuery postQuery) {

        String searchText = postQuery.getSearchText();
        // es 的分页是从0开始的 ！！！ 踩坑了
        long current = postQuery.getCurrent() - 1 ;
        long pageSize = postQuery.getPageSize();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 过滤
        boolQueryBuilder.filter(QueryBuilders.termQuery("isDelete", 0));

        // 按关键词检索
        if (org.apache.commons.lang3.StringUtils.isNotBlank(searchText)) {
            boolQueryBuilder.should(QueryBuilders.matchQuery("title", searchText));
            boolQueryBuilder.should(QueryBuilders.matchQuery("content", searchText));
            boolQueryBuilder.minimumShouldMatch(1);
        }

        // 分页
        PageRequest pageRequest = PageRequest.of((int) current, (int) pageSize);
        // 构造查询
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
                .withPageable(pageRequest)
                .build();
        SearchHits<PostEsDTO> searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);

        List<PostEsDTO> resultList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());

        List<SearchHit<PostEsDTO>> hitList = searchHits.getSearchHits();
        for (int i = 0; i < hitList.size(); i++) {
            Float score = hitList.get(i).getScore();
            resultList.get(i).setScore(score);
        }

        if (resultList.isEmpty()) {
            QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .should(QueryBuilders.wildcardQuery("title", "*" + searchText + "*"));

            searchQuery = new NativeSearchQuery(queryBuilder);
            searchHits = elasticsearchRestTemplate.search(searchQuery, PostEsDTO.class);
            resultList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        }


        Page<PostEsDTO> page = new Page<>();
        page.setTotal(searchHits.getTotalHits());  // 获取搜索到的总数
        page.setCurrent(postQuery.getCurrent());  // 获取当前页码
        page.setSize(postQuery.getPageSize()); // 获取页面大小
        page.setRecords(resultList);  // 获取数据源

        return page;
    }

    @Override
    public PostEsDTO getDto(Post post) {
        if (post == null) {
            return null;
        }
        PostEsDTO postEsDTO = new PostEsDTO();
        postEsDTO.setId(post.getId());
        postEsDTO.setTitle(post.getTitle());
        postEsDTO.setContent(post.getContent());
        String s = post.getTags();
        List<String> list = new Gson().fromJson(s, List.class);
        postEsDTO.setTags(list);
        postEsDTO.setUserId(post.getUserid());
        postEsDTO.setCreateTime(post.getCreatetime());
        postEsDTO.setUpdateTime(post.getUpdatetime());
        postEsDTO.setIsDelete(post.getIsdelete());

        return postEsDTO;
    }

    @Override
    public Page<PostVO> picEsListToPostVOPage(List<PictureEsDTO> pictureEsDTOList, PostQuery postQuery) {
        if (pictureEsDTOList.isEmpty()) {
            return null;
        }
        List<PostVO> result = new ArrayList<>();
        String keyWord = postQuery.getSearchText();
        // todo 一个文件可能匹配到了多个图片  解决
        // todo 图片分页
        long total = 0;
        Long fileId = -1L;
        for (PictureEsDTO pictureEsDTO : pictureEsDTOList) {
            if (fileId.equals(pictureEsDTO.getFileId())) {
                continue;
            }
            fileId = pictureEsDTO.getFileId();
            Post post = getById(fileId);
            PostVO postVO = new PostVO();
            postVO.setId(post.getId());
            postVO.setTitle(post.getTitle());
            postVO.setContent("");
            postVO.setOcrPicMsg(pictureEsDTO.getContent());
            postVO.setScore(0.0F);
            postVO.setLocator(null);
            postVO.setMatchWord(keyWord);
            String tags = post.getTags();
            List<String> tagList = new Gson().fromJson(tags, List.class);
            postVO.setTags(tagList);
            postVO.setThumbnum(post.getThumbnum());
            postVO.setDislikenum(post.getDislikenum());
            postVO.setDownloadnum(post.getDownloadnum());
            postVO.setUserid(post.getUserid());
            postVO.setCreatetime(post.getCreatetime());
            postVO.setImgtitle(pictureEsDTO.getImgtitle());
            result.add(postVO);
            total += 1;  // 统计总数（文件的总数）
        }

        Page<PostVO> page = new Page<>(postQuery.getCurrent(), postQuery.getPageSize());
        page.setTotal(total);
        int startIndex = (int) page.offset();
        int endIndex = Math.min(startIndex + (int) postQuery.getPageSize(), (int) total);
        if (startIndex > endIndex) {
            page.setRecords(new ArrayList<>()); // 设置空列表，因为没有数据
        } else {
            List<PostVO> subList = result.subList(startIndex, endIndex);
            page.setRecords(subList);
        }
        return page;
    }

    @Override
    public int giveAlike(String filename, String username) {
        if(userService.searchUser(username)!=null){
            Post post=postMapper.selectByName(filename);
            if(post!=null){
                int like=post.getThumbnum()+1;
                post.setThumbnum(like);
                return postMapper.updateById(post);
            }
            else  return 0;
        }
        return 0;
    }

    @Override
    public int giveAdislike(String filename, String username) {
        if(userService.searchUser(username)!=null){
        Post post=postMapper.selectByName(filename);
        if(post!=null){
            int dislike=post.getDislikenum()+1;
            post.setDislikenum(dislike);
            return postMapper.updateById(post);
        }
        else return 0;
        }
        return 0;
    }

    @Override
    public Page<Post> selectByTags(PostQuery postQuery) {
        long current = postQuery.getCurrent();
        long pageSize = postQuery.getPageSize();
        Page<Post> postPage = new Page<>(current, pageSize);
        String tags = postQuery.getTags();
        if (tags.isEmpty()){
            return postPage;
        }
        QueryWrapper<Post> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("tags", tags);
        postMapper.selectPage(postPage,queryWrapper);
        return postPage;
    }

    @Override
    public Page<PostByTagVO> getResultByTag(Page<Post> postPage, PostQuery postQuery) {
        Page<PostByTagVO> resultPage = new Page<>();
        resultPage.setTotal(postPage.getTotal());
        resultPage.setSize(postPage.getSize());
        resultPage.setCurrent(postPage.getCurrent());
        String username = postQuery.getUserName();
        List<PostByTagVO> resultList = new ArrayList<>();
        for(Post post: postPage.getRecords()){
            PostByTagVO postByTagVO = new PostByTagVO();
            postByTagVO.setId(post.getId());
            postByTagVO.setTitle(post.getTitle());
            int length = Math.min(post.getContent().length(), 300);
            postByTagVO.setContent(post.getContent().substring(0,length));
            postByTagVO.setMatchWord(postQuery.getTags());
            String tags = post.getTags();
            List<String> tagList = new Gson().fromJson(tags, List.class);
            postByTagVO.setTags(tagList);
            postByTagVO.setThumbnum(post.getThumbnum());
            postByTagVO.setDislikenum(post.getDislikenum());
            postByTagVO.setDownloadnum(post.getDownloadnum());
            postByTagVO.setUserid(post.getUserid());
            postByTagVO.setCreatetime(post.getCreatetime());
            postByTagVO.setIsfavorite(false);
            if(!username.isEmpty()){
                int userid=userService.searchUser(username).getId();
                if(favoriteService.seleteFavoriteFile(post.getTitle(),userid)){
                    postByTagVO.setIsfavorite(true);
                }
            }
            resultList.add(postByTagVO);
        }
        resultPage.setRecords(resultList);
        return resultPage;
    }

    @Override
    public boolean addDownloadNum(String fileName) {
        Post post = postMapper.selectByName(fileName);
        post.addDownload(1);
        int update = postMapper.updateById(post);
        return update > 0;
    }

    @Override
 public Page<PostVO> getResult(Page<PostEsDTO> esDTOPage, String keyword,String username) {
        if (esDTOPage.getTotal() == 0) {
            return null;
        }
        Page<PostVO> page = new Page<>();
        page.setTotal(esDTOPage.getTotal());
        page.setSize(esDTOPage.getSize());
        page.setCurrent(esDTOPage.getCurrent());
        List<PostVO> resultList = new ArrayList<>();
        for (PostEsDTO postEsDTO : esDTOPage.getRecords()) {
            PostVO post = new PostVO();
            post.setId(postEsDTO.getId());
            post.setTitle(postEsDTO.getTitle());

            if(!username.isEmpty()){
                int userid=userService.searchUser(username).getId();
                if(favoriteService.seleteFavoriteFile(postEsDTO.getTitle(),userid)){
                    post.setIsfavorite(true);
                }
            }
            String matchWord = "";  // 用来定位匹配到的关键词
            String content = postEsDTO.getContent();
            String keyWordAbs = MyUtils.getKeyWordAbs(content, keyword);
            // 如果没有获取到摘要，就对关键词进行分词，在找一遍
            if (keyWordAbs.isEmpty()) {
                List<String> segments = MyUtils.segmentText(keyword);
                for (String segment : segments) {
                    keyWordAbs = MyUtils.getKeyWordAbs(content, segment);
                    if (!keyWordAbs.isEmpty()) {
                        matchWord = segment;
                        break;
                    }
                }
            }
            post.setContent(keyWordAbs);

            if (matchWord.isEmpty()) {
                matchWord = keyword;
            }
            post.setMatchWord(matchWord);

            post.setUserid(postEsDTO.getUserId());
            post.setCreatetime(postEsDTO.getCreateTime());
            post.setTags(postEsDTO.getTags());

            // ES中没有存储点赞量、点踩量、下载量,需要从数据库中获取
            Post byId = postMapper.selectById(postEsDTO.getId());
            Integer thumbnum = byId.getThumbnum();
            Integer dislikenum = byId.getDislikenum();
            Integer downloadnum = byId.getDownloadnum();
            post.setThumbnum(thumbnum);
            post.setDislikenum(dislikenum);
            post.setDownloadnum(downloadnum);

            String fileName = postEsDTO.getTitle();
            Map<String, Integer> locator = MyUtils.getKeywordLocator(matchWord, fileName);

            post.setLocator(locator);

            // 匹配图片  todo 还没有对图片信息做摘要
            List<PictureEsDTO> picFromEs = pictureService.getPicFromEs(keyword, post.getId());
            if (!picFromEs.isEmpty()) {
                post.setOcrPicMsg(picFromEs.get(0).getContent());
                post.setImgtitle(picFromEs.get(0).getImgtitle());
            }
            Float score = postEsDTO.getScore();
            score = MyUtils.calScore(score, thumbnum, dislikenum, downloadnum);
            post.setScore(score);

            resultList.add(post);
        }
        // 使用Stream对resultList按照下载量降序排序
        List<PostVO> sortedList = resultList.stream()
                .sorted(Comparator.comparing(PostVO::getScore).reversed())
                .collect(Collectors.toList());


        page.setRecords(sortedList);
        return page;
    }

}




